package com.leyou.trade.service.impl;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.leyou.common.exception.LyException;
import com.leyou.dto.AddressDTO;
import com.leyou.item.client.ItemClient;
import com.leyou.item.dto.SkuDTO;
import com.leyou.trade.constants.PayConstants;
import com.leyou.trade.dto.OrderFormDTO;
import com.leyou.trade.entity.Order;
import com.leyou.trade.entity.OrderDetail;
import com.leyou.trade.entity.OrderLogistics;
import com.leyou.trade.enums.OrderStatus;
import com.leyou.trade.enums.TradeState;
import com.leyou.trade.mapper.OrderMapper;
import com.leyou.trade.service.OrderService;
import com.leyou.trade.utils.PayHelper;
import com.leyou.trade.utils.UserHolder;
import com.leyou.user.client.UserClient;
import feign.FeignException;
import io.seata.spring.annotation.GlobalTransactional;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.validation.Valid;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

/**
 * @author 虎哥
 */
@Service
public class OrderServiceImpl extends ServiceImpl<OrderMapper, Order> implements OrderService {

    private OrderDetailServiceImpl detailService;

    private OrderLogisticsServiceImpl logisticsService;

    private ItemClient itemClient;

    private UserClient userClient;

    private CartServiceImpl cartService;

    @Autowired
    private PayHelper payHelper;
    public OrderServiceImpl(OrderDetailServiceImpl detailService, OrderLogisticsServiceImpl logisticsService, ItemClient itemClient, UserClient userClient, CartServiceImpl cartService) {
        this.detailService = detailService;
        this.logisticsService = logisticsService;
        this.itemClient = itemClient;
        this.userClient = userClient;
        this.cartService = cartService;
    }

    @Override
    @GlobalTransactional
    public Long createOrder(@Valid OrderFormDTO orderDTO) {
        Map<Long, Integer> cartGoods = orderDTO.getCarts();
        LinkedList<Long> skuIds = new LinkedList<>(cartGoods.keySet());
        List<SkuDTO> skuDTOS = itemClient.querySkuByIds(skuIds);
        Long totalFee = 0L;
        List<OrderDetail> orderDetails = new LinkedList<>();
        for (SkuDTO skuDTO : skuDTOS) {
            Integer skuNum = cartGoods.get(skuDTO.getId());
            totalFee += skuNum * skuDTO.getPrice();
            //封装orderDetail,  计算价格
            OrderDetail orderDetail = new OrderDetail();
            orderDetail.setTitle(skuDTO.getTitle());
            orderDetail.setSpec(skuDTO.getSpecialSpec());
            orderDetail.setSkuId(skuDTO.getId());
            orderDetail.setPrice(skuDTO.getPrice());
            orderDetail.setImage(StringUtils.substringBefore(skuDTO.getImages(), ","));
            orderDetail.setNum(skuNum);
            orderDetails.add(orderDetail);
        }
        //创建订单,添加到数据库
        Order order = new Order();
        order.setUserId(UserHolder.getUser());
        order.setTotalFee(totalFee);
        order.setStatus(OrderStatus.INIT);
        order.setPostFee(0L);
        order.setPaymentType(orderDTO.getPaymentType());
        order.setActualFee(totalFee - order.getPostFee());
        boolean flag = save(order);
        if (!flag) throw  new LyException(500, "生成订单失败");
        //创建订单详情,每个商品详情添加进去,添加到数据库
        orderDetails.forEach(orderDetail -> orderDetail.setOrderId(order.getOrderId()));
        flag = detailService.saveBatch(orderDetails);
        if (!flag) throw  new LyException(500, "生成订单失败");
        //添加物流信息
        // 3.写orderLogistics
        // 3.1.查询收货地址
        AddressDTO address = userClient.queryAddressById(orderDTO.getAddressId());
        // 3.2.填写物流信息
        OrderLogistics logistics = address.toEntity(OrderLogistics.class);
        logistics.setOrderId(order.getOrderId());
        // 3.3.写入数据库
        flag = logisticsService.save(logistics);
        if (!flag) throw  new LyException(500, "生成订单失败");
        try {
            itemClient.deductStock(cartGoods);
        } catch (FeignException e) {
            throw new LyException(e.status(), e.contentUTF8());
        }
        //删除购物车信息
        skuIds.forEach(cartService::deleteCart);

        return order.getOrderId();
    }

    @Override
    public String getPayUrl(Long orderId) {
        /**
         * 根据订单id获取一个url连接返回给前端，生成二维码
         */
        Order order = getById(orderId);
        //健壮性判断
        if (order == null) throw new LyException(400, "订单不存在");
        if (OrderStatus.INIT != order.getStatus()) throw new LyException(400, "无需重复付款");
        String url;
        try {
            url = payHelper.unifiedOrder(orderId, order.getActualFee());
        } catch (Exception e) {
            throw new LyException(400, "生成url失败");
        }
        return url;
    }

    @Override
    @Transactional
    public void handleNotify(Map<String, String> data) {
        //做各种检验
        try {
            payHelper.checkResultCode(data);
            payHelper.checkReturnCode(data);
            payHelper.checkSignature(data);
        } catch (Exception e) {
            throw new LyException(400, "有内鬼，停止交易");
        }
        Long totalFee = Long.valueOf(data.get(PayConstants.TOTAL_FEE_KEY));
        //和数据库的金额作对比， 要保证幂等性和并发运行下的线程安全问题
        Order order = getById(data.get(PayConstants.ORDER_NO_KEY));
        if (order == null) {
            throw new LyException(400, "并没有订单怎么付款呢");
        }

        if (totalFee != order.getActualFee()) {
            throw new LyException(400, "钱不对，已报警");
        }
        //保证幂等性， 乐观锁
        update()
                .set("status", OrderStatus.PAY_UP.getValue())
                .set("pay_time", new java.util.Date())
                .eq("status", OrderStatus.INIT.getValue())
                .eq("order_id", data.get(PayConstants.ORDER_NO_KEY))
                .update();




    }
    @Override
    public Integer queryOrderState(Long orderId) {
        // 查询订单
        Order order = getById(orderId);
        // 判断是否存在
        if (order == null) {
            throw new LyException(400, "订单不存在！");
        }
        return order.getStatus().getValue();
    }

    @Override
    public Integer queryOrderStatus(Long orderId) {
        String stradeState = payHelper.queryOrder(orderId);
        if (TradeState.SUCCESS.getMsg().equals(stradeState)) {
            return TradeState.SUCCESS.getValue();
        }
        for (TradeState tradeState : TradeState.values()) {
            if (tradeState.getMsg().equals(stradeState)) {
                return tradeState.getValue();
            }
        }
        return 0;
    }

}